﻿#include "JsonUtil.h"
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>
#include <QFile>
#include <QFileInfo>
#include <QCoreApplication>
#include <QDebug>

namespace JsonUtil {


bool loadJson(const QString &filePath, QVariantMap &map)
{
    QFile file(filePath);
    if (!file.open(QIODevice::ReadOnly))
    {
        qDebug() << "loadJson fail: " << filePath;
        file.close();
        return false;
    }

    //    QString fileStr = QString(file.readAll());
    //    QJsonDocument loadDoc(QJsonDocument::fromJson(fileStr.toUtf8()));

    QJsonDocument loadDoc(QJsonDocument::fromJson(file.readAll()));

    file.close();
    map = loadDoc.object().toVariantMap();

    return true;
}

bool saveJson(const QVariantMap &map, QString filePath)
{
    QFile file(filePath);
    if (!file.open(QIODevice::WriteOnly))
    {
        qDebug() << "loadJson 2 fail";
        file.close();
        return false;
    }

    QVariantMap mapEng = map;

    QJsonDocument saveDoc(QJsonObject::fromVariantMap(mapEng));

    QString fileStr = QString(saveDoc.toJson());


    //    file.write(saveDoc.toJson());
    file.write(fileStr.toUtf8());

    file.close();

    return true;
}


bool saveJson(const QVariantList &varList, QString filePath)
{
    QFile file(filePath);
    if (!file.open(QIODevice::WriteOnly))
    {
        qDebug() << "loadJson 3 fail";
        file.close();
        return false;
    }

    QJsonDocument saveDoc(QJsonArray::fromVariantList(varList));

    QString fileStr = QString(saveDoc.toJson());


    file.write(saveDoc.toJson());
    //    file.write(fileStr.toUtf8());

    file.close();

    return true;
}



bool loadJson(const QString& filePath, QVariant &variant)
{
    QFile file(filePath);
    if (!file.open(QIODevice::ReadOnly))
    {
        qDebug() << "loadJson 4 fail";
        file.close();
        return false;
    }

    //    QString fileStr = QString(file.readAll());
    //    QJsonDocument jsonDoc(QJsonDocument::fromJson(fileStr.toUtf8()));

    QJsonDocument jsonDoc(QJsonDocument::fromJson(file.readAll()));
    file.close();

    variant = jsonDoc.object();

    return true;
}

QVariantMap jsonStr2map(const QString& jsonStr)
{
    QJsonDocument jsonDoc(QJsonDocument::fromJson(jsonStr.toUtf8()));
    return jsonDoc.toVariant().toMap();
}


bool byteArray2VarMap(QByteArray &byteArray, QVariantMap &map)
{
    QJsonDocument jsonDoc(QJsonDocument::fromJson(byteArray));
    map = jsonDoc.object().toVariantMap();

    if (map.isEmpty())
    {
        return false;
    }
    return true;
}


bool variant2ByteArray(const QVariant &variant, QByteArray &byteArray)
{
    QJsonDocument jsonDoc(QJsonDocument::fromVariant(variant));
    byteArray = jsonDoc.toJson();
    if (byteArray.isEmpty())
    {
        return false;
    }
    return true;
}


bool varMap2ByteArray(QVariantMap &map, QByteArray &byteArray)
{
    QJsonDocument saveDoc(QJsonObject::fromVariantMap(map));
    byteArray = saveDoc.toJson();

    if (byteArray.isEmpty())
    {
        return false;
    }
    return true;
}


bool loadJson(const QString& filePath, QVariantList &varList)
{
    QFile file(filePath);
    if (!file.open(QIODevice::ReadOnly))
    {
        file.close();
        return false;
    }

    //    QString fileStr = QString(file.readAll());
    //    QJsonDocument loadDoc(QJsonDocument::fromJson(fileStr.toUtf8()));

    QJsonDocument loadDoc(QJsonDocument::fromJson(file.readAll()));

    file.close();
    varList = loadDoc.array().toVariantList();
    return true;
}

QVariantList jsonStr2List(const QString &jsonStr)
{
    QJsonDocument jsonDoc(QJsonDocument::fromJson(jsonStr.toUtf8()));
    return jsonDoc.array().toVariantList();
}

QString map2jsonStr(const QVariantMap& map)
{
    QJsonDocument doc(QJsonObject::fromVariantMap(map));
    return QString(doc.toJson());
}

void saveJsonForce(const QVariantMap &map, QString filePath)
{
    QFile file(filePath);
    file.open(QIODevice::WriteOnly | QIODevice::Truncate);

    QVariantMap mapEng = map;

    QJsonDocument saveDoc(QJsonObject::fromVariantMap(mapEng));

    QString fileStr = QString(saveDoc.toJson());

    file.write(fileStr.toUtf8());

    file.close();
}

QByteArray getBigEndianInt(int n)
{
    int num = n;
    QByteArray baRet;
    for (int i=0; i<4; ++i)
    {
        //        baRet << (quint8)(n&0xff)
        quint8 u8 = num&0xff;
//        qDebug() << "u8: " << QString::number(u8, 16);
        baRet.prepend(u8);
        num >>= 8;
    }

    return baRet;
}

QByteArray packData(const QVariantMap &json, const QByteArray &data)
{
    /// 0xef ef ef ef
    /// json size (big endian)
    /// json data
    /// binary data size (big endian)
    /// binary data
    QByteArray baRet;
    for (int i=0; i<4; ++i)
    {
//        baRet.append(quint8(0xef));
        baRet.append(quint8(0xEF));
    }

    QJsonDocument doc(QJsonObject::fromVariantMap(json));
    QByteArray baJson = doc.toJson();

    int nJsonSize = baJson.size();

    baRet.append(getBigEndianInt(nJsonSize));

    baRet.append(baJson);


//    qDebug() << "pack data size: " << data.size();

    baRet.append(getBigEndianInt(data.size()));
    if (data.size() > 0)
    {
        baRet.append(data);
    }

    return baRet;
}

QByteArray packDataFE(const QVariantMap &json, const QByteArray &data)
{
    /// 0xfe fe fe fe
    /// json size (big endian)
    /// json data
    /// binary data size (big endian)
    /// binary data
    QByteArray baRet;
    for (int i=0; i<4; ++i)
    {
//        baRet.append(quint8(0xfe));
        baRet.append(quint8(0xFE));
    }

    QJsonDocument doc(QJsonObject::fromVariantMap(json));
    QByteArray baJson = doc.toJson();

    int nJsonSize = baJson.size();

    baRet.append(getBigEndianInt(nJsonSize));

    baRet.append(baJson);

    baRet.append(getBigEndianInt(data.size()));
    if (data.size() > 0)
    {
        baRet.append(data);
    }

    return baRet;
}

}
